// Copyright 2013 wetalk authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package models

import (
	"fmt"
	"time"

	"errors"
	"git.oschina.net/lijinchao2007/wetalk/modules/mongo"
	"git.oschina.net/lijinchao2007/wetalk/modules/utils"
	"git.oschina.net/lijinchao2007/wetalk/setting"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"github.com/beego/i18n"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"reflect"
	"strings"
)

const PostModelName = "post"
const CommentModelName = "comment"

// post content
type Post struct {
	Id           int
	Id_          bson.ObjectId `bson:"_id,omitempty"`
	UserId       bson.ObjectId ``
	LastReplyId  bson.ObjectId ``
	LastAuthorId bson.ObjectId ``
	TopicId      bson.ObjectId ``
	CategoryId   bson.ObjectId ``
	User         *User         `-`
	LastReply    *User         `-`
	LastAuthor   *User         `-`
	Topic        *Topic        `-`
	Category     *Category     `-`
	Title        string        `orm:"size(60)"`
	Content      string        `orm:"type(text)"`
	ContentCache string        `orm:"type(text)"`
	Browsers     int           `orm:"index"`
	Replys       int           `orm:"index"`
	Favorites    int           `orm:"index"`
	Lang         int           `orm:"index"`
	IsBest       bool          `orm:"index"`
	Created      time.Time     `orm:"auto_now_add"`
	Updated      time.Time     `orm:"auto_now;index"`
}

func init() {
	beego.Info("reg post cb")

}

func (m *Post) Insert() error {
	m.Id_ = bson.NewObjectId()
	m.Created = time.Now()
	m.Updated = time.Now()
	if err := mongo.GetCollection(PostModelName).Insert(m); err != nil {
		return err
	}
	return nil
}

func (m *Post) Read(fields ...string) error {
	if len(fields) == 0 {
		if err := mongo.GetCollection(PostModelName).Find(bson.M{"_id": m.Id_}).One(m); err != nil {
			return err
		}
	} else if len(fields) == 1 {
		v := reflect.ValueOf(m).Elem().FieldByName(fields[0])
		set := bson.M{strings.ToLower(fields[0]): v.String()}
		if err := mongo.GetCollection(PostModelName).Find(set).One(m); err != nil {
			beego.Info("Read PostModelName err ", err)
			return err
		}
	} else {
		return errors.New("read PostModelName for to Much fields")
	}

	return nil
}

func (m *Post) Update(fields ...string) error {
	cond := bson.M{"_id": m.Id_}
	m.Updated = time.Now()
	if err := mongo.GetCollection(PostModelName).Update(cond, m); err != nil {
		return err
	}
	return nil
}

func (m *Post) AddBrowser() error {
	cond := bson.M{"_id": m.Id_}
	m.Browsers += 1
	u := bson.M{"$inc": bson.M{"browsers": 1}}
	if err := mongo.GetCollection(PostModelName).Update(cond, u); err != nil {
		return err
	}
	return nil
}
func (m *Post) CommentsCount() (int, error) {
	if count, err := mongo.GetCollection(CommentModelName).Find(bson.M{"postid": m.Id_}).Count(); err != nil {
		return 0, err
	} else {
		return count, nil
	}

}

func (m *Post) Delete() error {
	if err := mongo.GetCollection(PostModelName).RemoveId(m.Id_); err != nil {
		return err
	}
	return nil
}

func (m *Post) String() string {
	return utils.ToStr(m.Id_.Hex())
}

func (m *Post) Link() string {
	return fmt.Sprintf("%spost/%s", setting.AppUrl, m.Id_.Hex())
}

func (m *Post) GetContentCache() string {
	if setting.RealtimeRenderMD {
		return utils.RenderMarkdown(m.Content)
	} else {
		return m.ContentCache
	}
}

func (m *Post) Comments() orm.QuerySeter {
	return Comments().Filter("Post", m.Id_)
}

func (m *Post) GetLang() string {
	return i18n.GetLangByIndex(m.Lang)
}

func Posts() *mgo.Collection {
	return mongo.GetCollection(PostModelName)
}

// commnet content for post
type Comment struct {
	Id           int
	Id_          bson.ObjectId `bson:"_id,omitempty"`
	UserId       bson.ObjectId ``
	PostId       bson.ObjectId ``
	PostIdd      *mgo.DBRef    ``
	User         *User         `-`
	Post         *Post         `-`
	Message      string        `orm:"type(text)"`
	MessageCache string        `orm:"type(text)"`
	Floor        int
	Status       int
	Created      time.Time `orm:"auto_now_add;index"`
}

func (m *Comment) Insert() error {
	m.Id_ = bson.NewObjectId()
	m.Created = time.Now()
	//	beego.Info("insert Comment ", *m)
	if err := mongo.GetCollection(CommentModelName).Insert(m); err != nil {
		return err
	}
	return nil
}

func (m *Comment) Read(fields ...string) error {
	if len(fields) == 0 {
		if err := mongo.GetCollection(CommentModelName).Find(bson.M{"_id": m.Id_}).One(m); err != nil {
			return err
		}
	} else if len(fields) == 1 {
		v := reflect.ValueOf(m).Elem().FieldByName(fields[0])
		set := bson.M{strings.ToLower(fields[0]): v.String()}
		if err := mongo.GetCollection(CommentModelName).Find(set).One(m); err != nil {
			beego.Info("Read CommentModelName err ", err)
			return err
		}
	} else {
		return errors.New("read CommentModelName for to Much fields")
	}

	return nil
}

func (m *Comment) Update(fields ...string) error {
	cond := bson.M{"_id": m.Id_}
	if err := mongo.GetCollection(CommentModelName).Update(cond, m); err != nil {
		return err
	}
	return nil
}

func (m *Comment) Delete() error {
	if err := mongo.GetCollection(CommentModelName).RemoveId(m.Id_); err != nil {
		return err
	}
	return nil
}

func (m *Comment) GetMessageCache() string {
	if setting.RealtimeRenderMD {
		return utils.RenderMarkdown(m.Message)
	} else {
		return m.MessageCache
	}
}

func (m *Comment) String() string {
	return utils.ToStr(m.Id)
}

func Comments() orm.QuerySeter {
	return orm.NewOrm().QueryTable("comment").OrderBy("-Id")
}

// user favorite posts
type FavoritePost struct {
	Id      int
	User    *User     `orm:"rel(fk)"`
	Post    *Post     `orm:"rel(fk)"`
	Created time.Time `orm:"auto_now_add"`
}

func (*FavoritePost) TableUnique() [][]string {
	return [][]string{
		[]string{"User", "Post"},
	}
}

func init() {
	//	orm.RegisterModel(new(Post), new(FavoritePost), new(Comment))
}
